<script lang="ts">
import { ref, h, withModifiers, watchEffect } from 'vue'
import type { VNode } from 'vue'
import type { Object3D } from 'three'
import { useViewportStore } from '@renderer/stores/viewport'
import { storeToRefs } from 'pinia'
import { useActiveObject } from '@renderer/stores/activeObject'
import { ElInput } from 'element-plus'
import emiter from '@renderer/utils/mitt'
import useEditor from '@renderer/utils/useEditor'

export interface DragObject extends Object3D {
  parent: DragObject
  children: DragObject[]
  _dragClass?: 'dragTop' | 'dragBottom' | 'drag' | ''
  _collapsed: boolean
}

export default {
  setup() {
    const viewportStore = useViewportStore()
    const { publicGroup } = storeToRefs(viewportStore)
    const dataList = ref<DragObject[]>([])

    emiter.on('viewChange', () => {
      dataList.value = undefined
      dataList.value = publicGroup.value?.children
    })

    // 点击选中节点
    const activeObjectStore = useActiveObject()
    const { activeShallowRef } = storeToRefs(activeObjectStore)
    function handleClickNode(data: Object3D) {
      activeObjectStore.setActiveVO(data)
    }
    // 当前被拖拽的节点
    const currentDrag = ref<DragObject>()
    // 开始拖拽
    function handleDrag(data: DragObject) {
      currentDrag.value = data
    }
    // 拖拽中
    function handleDragOver(
      e: { offsetY: number; target: { clientHeight: number } },
      data: DragObject
    ) {
      const area = e.offsetY / e.target.clientHeight
      if (area < 0.25) {
        data._dragClass = 'dragTop'
      } else if (area > 0.75) {
        data._dragClass = 'dragBottom'
      } else {
        data._dragClass = 'drag'
      }
    }

    function handleDragLeave(data: DragObject) {
      data._dragClass = ''
    }
    // 拖拽结束放下
    function handleDrop(data: DragObject) {
      if (!currentDrag.value || data.uuid === currentDrag.value.uuid) return

      const parent = data.parent
      if (data._dragClass === 'dragTop') {
        const nextObject = data
        moveObject(currentDrag.value, parent, nextObject)
      } else if (data._dragClass === 'drag') {
        const cantMove = containsObject(currentDrag.value, data)

        if (!cantMove) {
          moveObject(currentDrag.value, data)
        }
      } else if (data._dragClass === 'dragBottom') {
        const nextObject = data.parent.children[data.parent.children.indexOf(data) + 1] || null
        moveObject(currentDrag.value, parent, nextObject)
      }

      data._dragClass = ''
    }
    // 移动对象的函数
    function moveObject(data: DragObject, newParent: DragObject, nextObject?: DragObject) {
      const oldParent = data.parent
      oldParent.remove(data)
      let newIndex = null

      if (nextObject) {
        newIndex = newParent?.children.indexOf(nextObject)
      } else {
        newIndex = newParent?.children.length
      }

      newParent.children.splice(newIndex, 0, data)
      data.parent = newParent
    }

    // 判断是否包含有当前节点
    function containsObject(parent: DragObject, child: DragObject) {
      if (parent === child) {
        return true
      }

      for (let i = 0; i < parent.children.length; i++) {
        if (containsObject(parent.children[i], child)) {
          return true
        }
      }

      return false
    }
    // 切换可见性
    const { closeEditor } = useEditor()
    function changVisibility(data, visible) {
      data.visible = visible ? visible : !data.visible
      if (data.type === 'Group') {
        data.children.forEach((child) => {
          changeCollapsed(child)
        })
      }
      if (data._isEditor) {
        closeEditor()
        data._isEditor = false
      }
      // TODO
    }
    // 获取类型的图标
    function getTypeIcon(type: string) {
      switch (type) {
        case 'group':
          return 'icon-zu'
        case 'roadway':
          return 'icon-xiangdao'
        case '001':
          return 'icon-base-signal-full'
        case '002':
          return 'icon-chuanganqi2'
        case '003':
          return 'icon-bayonet-camera-full'
        default:
          return ''
      }
    }
    // 切换收缩和展开
    function changeCollapsed(data: DragObject) {
      data._collapsed = !data._collapsed
    }

    // 递归渲染
    function recursionRender(dataList: DragObject[], isChild: number) {
      const eles: VNode[] = []
      if (dataList?.length) {
        dataList.forEach((data) => {
          if (data.name === 'editor' || data.type === 'Object3D') return
          if (data.name.includes(keywords.value) || !keywords.value) {
            const node = h(
              'div',
              {
                class: [
                  'data-item',
                  data._dragClass ? data._dragClass : '',
                  { active: data.uuid === activeShallowRef.value?.uuid }
                ],
                style: { marginLeft: `${18 * isChild + (data.children.length ? 0 : 14)}px` },
                draggable: true,
                title: data.name,
                ondrag: () => handleDrag(data),
                ondragover: withModifiers(
                  ($event: any) => handleDragOver($event, data),
                  ['prevent']
                ),
                ondragleave: () => handleDragLeave(data),
                ondrop: () => handleDrop(data),
                onclick: () => handleClickNode(data)
              },
              [
                data.children.length
                  ? h('i', {
                      class: `collapsed iconfont ${data._collapsed ? 'icon-arrow_right_fat' : 'icon-xiajiantou'}`,
                      onclick: withModifiers(() => changeCollapsed(data), ['stop'])
                    })
                  : null,
                h('span', { class: 'data-item--name' }, [
                  data.name,
                  (() => {
                    if (data.userData.type === 'equipment') {
                      const arr = data.userData.detailDtos?.map((item) =>
                        h('i', { class: `iconfont ${getTypeIcon(item.deviceType)}` })
                      )
                      return arr
                    } else {
                      return h('i', { class: `iconfont ${getTypeIcon(data.userData.type)}` })
                    }
                  })()
                ]),
                h('i', {
                  class: `iconfont ${data.visible ? 'icon-see' : 'icon-bukejian'}`,
                  onClick: withModifiers(() => changVisibility(data), ['stop'])
                })
              ]
            )
            eles.push(node)
          }
          if (data.children?.length && !data._collapsed) {
            const child = recursionRender(data.children, isChild + 1)
            eles.push(...child)
          }
        })
      }
      return eles
    }

    // 获取当前高亮的元素并在视口显示
    watchEffect(() => {
      const i = getLightHeight(dataList.value)
      console.log(i)
      function getLightHeight(dataList, i = 0) {
        dataList.forEach((node, index) => {
          if (activeShallowRef.value) {
            i += index
            if (node.uuid === activeShallowRef.value.uuid) {
              return i
            } else if (node.children) {
              getLightHeight(node.children, i)
            }
          }
        })
      }
    })

    const keywords = ref()
    function filterNode(val) {
      keywords.value = val
    }
    return () =>
      h('div', { class: 'outliner' }, [
        h(ElInput, {
          modelValue: keywords.value,
          'onUpdate:modelValue': filterNode,
          class: 'filterInput'
        }),
        h('div', { class: 'outliner-box' }, [recursionRender(dataList.value, 0)])
      ])
  }
}
</script>
<style lang="scss" scoped>
.outliner {
  display: flex;
  flex-direction: column;
  background-color: var(--box-background);
  padding: 5px;
  height: 240px;
  resize: vertical;
  overflow-x: hidden;
  overflow-y: auto;
  user-select: none;
}

.filterInput {
  margin-bottom: 10px;
}

.outliner-box {
  flex: 1;
  overflow: auto;
}

.data-item {
  font-size: 12px;
  padding: 4px;
  line-height: 1.2em;
  border: 1px solid transparent;
  margin-bottom: 2px;
  display: flex;

  &:hover,
  &.active {
    background-color: var(--input-background);
    color: var(--active-color);
  }

  &.drag {
    border: 1px dashed var(--active-background);
  }

  &.dragTop {
    border-top: 1px dashed var(--active-background);
  }

  &.dragBottom {
    border-bottom: 1px dashed var(--active-background);
  }

  .data-item--name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;

    & > .iconfont {
      margin-left: 6px;
      font-size: 12px;
    }
  }

  & > .iconfont {
    cursor: pointer;
  }

  .collapsed {
    font-size: 12px;
    margin-right: 4px;
  }
}
</style>
